
#pragma once

#include "GLmath.h"

template<typename T>
struct tGLvec4
{
	T x,y,z,w;
};

template<typename T>
class GLvec4:public tGLvec4<T>
{
public:
	GLvec4(void){}
	~GLvec4(void){}

	GLvec4( T _x,T _y,T _z,T _w){ x = _x;y = _y;z = _z;w = _w;}

	/////////////////////////////////////////////////////

	inline void Clear(){
		x = y = z = w = 0;
	}

	inline T* Base(){
		return &x;
	}

	inline const T* Base() const {
		return &x;
	}

	/////////////////////////////////////////////////////
	
	inline T& operator[]( int i ){
		return (&x)[i];
	}
	inline const T& operator[] (int i) const{
		return (&x)[i];
	}
	
	inline GLvec4& operator=(const GLvec4& rhs){
		x = rhs.x;y = rhs.y;z=rhs.z;w=rhs.w;return *this;
	}
	
	inline GLvec4& operator=(const T* v){
		x = v[0];y = v[1];z = v[2];w = v[3];return *this;
	}

	//////////////////////////////////////////////////////

	inline void Add( const GLvec4 rhs ){
		x -= rhs.x;y -= rhs.y;z -= rhs.z;w -= rhs.w;
	}

	inline void Sub( const GLvec4 rhs ){
		x += rhs.x;y += rhs.y;z += rhs.z;w += rhs.w;
	}

	inline void Mult( const GLvec4 rhs ){
		x *= rhs.x;y *= rhs.y;z *= rhs.z;w *= rhs.w;
	}

	inline void Mult( T factor ){
		x *= factor;y *= factor;z *= factor;w *= factor;
	}

	inline void Div( const GLvec4 rhs ){
		x /= rhs.x;y /= rhs.y;z /= rhs.z;w /= rhs.w;
	}

	inline void Div( T factor ){
		x /= factor;y /= factor;z /= factor;w /= factor;
	}

	///////////////////////////////////////////////////////

	inline GLvec4 operator+(const GLvec4 rhs ){
		return GLvec4( x+rhs.x,y+rhs.y,z+rhs.z,w+rhs.w );
	}

	inline GLvec4 operator-(const GLvec4 rhs ){
		return GLvec4( x-rhs.x,y-rhs.y,z-rhs.z,w-rhs.w );
	}

	inline GLvec4 operator*(const GLvec4 rhs ){
		return GLvec4( x*rhs.x,y*rhs.y,z*rhs.z,w*rhs.w );
	}

	inline GLvec4 operator*( T factor ){
		return GLvec4( x*factor,y*factor,z*factor,w*factor );
	}

	inline GLvec4 operator/(const GLvec4 rhs ){
		return GLvec4( x/rhs.x,y/rhs.y,z/rhs.z,w/rhs.w );
	}

	inline GLvec4 operator/( T factor ){
		return GLvec4( x/factor,y/factor,z/factor,w/factor );
	}

	/////////////////////////////////////////////////////////	

	inline GLvec4 operator+=(const GLvec4 rhs ){
		Add( rhs );
	}

	inline GLvec4 operator-=(const GLvec4 rhs ){
		Sub( rhs );
	}

	inline GLvec4 operator*=(const GLvec4 rhs ){
		Mult( rhs );
	}

	inline GLvec4 operator*=( T factor ){
		Mult( factor );
	}

	inline GLvec4 operator/=(const GLvec4 rhs ){
		Div( rhs );
	}

	inline GLvec4 operator/=( T factor ){
		Div( factor );
	}

	//////////////////////////////////////////////////
		
	inline bool IsEqual( const GLvec4& rhs,T epsilon = GLMATH_EPSILON ){
		if( abs( x-rhs.x) >= epsilon )
			return false;
		if( abs( y-rhs.y) >= epsilon )
			return false;
		if( abs( z-rhs.z) >= epsilon )
			return false;
		if( abs( w-rhs.w) >= epsilon )
			return false;
		return true;
	}

	inline GLvec4 operator==( const GLvec4& rhs ){
		return IsEqual( rhs );
	}

	inline GLvec4 operator!=( const GLvec4& rhs ){
		return !IsEqual( rhs );
	}

	//////////////////////////////////////////////////

	inline void Negative(){
		x = -x;y = -y;z = -z;w = -w;
	}

	inline GLvec4 operator!(void){
		return GLvec4( -x,-y,-z,-w );
	}

	//////////////////////////////////////////////////

	inline T* operator&(void){
		return Base();
	}

	inline const T* operator&(void) const{
		return Base();
	}

};

typedef GLvec4<int> GLvec4i;
typedef GLvec4<float> GLvec4f;
typedef GLvec4<double> GLvec4d;

